#include "../../Base/stdafx.h"
#include "../../Base/DXDevice.h"
#include "../../Base/GameEngine.h"
#include "OBJMesh.h"
#include "../../Base/Vertex.h"
#include "../../Base/StringUtil.h"
#include "../../PhysX/PhysX.h"
#include "../../Time/Counter.h"
#include <boost/foreach.hpp>
#include "../../Effects/EffectShadow.h"
#include "../../Effects/EffectAnim.h"
#include "../../Animatie/Skeleton.h"

OBJMesh::OBJMesh(const MeshDesc& mDesc, const D3DXVECTOR3& pos, const D3DXVECTOR3& rot, const D3DXVECTOR3& scale): m_Skeleton(0)
{
	tstring file = mDesc.name;
	Counter mCounter; mCounter.Start();

	tifstream input(file.c_str());
	if(!input) 
		LOG(tstring(_T("ERROR: Kan ") + file + _T(" niet inladen.\n")).c_str());

	tstring line;
	while(!input.eof())
	{
		getline(input, line);
		StringUtil::TrimWhiteSpace(line);

		if(line.find(_T("mtllib"), 0) == 0)
			ReadMaterial(line);
		else if(line.find(_T("vn"), 0) == 0)
			ReadNormal(line);
		else if(line.find(_T("vt"), 0) == 0)
			ReadTexture(line);
		else if(line.find(_T("v"), 0) == 0)
			ReadVertice(line);
		else if(line.find(_T("f"), 0) == 0)
			ReadFaces(line);
	}

	input.close();

	CalculateMesh();


	D3D10_INPUT_ELEMENT_DESC Layout[] =
	{
		{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0},
		{ "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D10_INPUT_PER_VERTEX_DATA, 0},
		{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 24, D3D10_INPUT_PER_VERTEX_DATA, 0},
		{ "TANGENT", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 32, D3D10_INPUT_PER_VERTEX_DATA, 0},
	};

	HR(D3DX10CreateMesh(GETDEVICE, Layout, 4, Layout[0].SemanticName, m_VertexList.size(), m_Faces.size()/3, D3DX10_MESH_32_BIT, &m_Mesh));

	SetTranslate(pos);
	SetRotation(rot);
	SetScale(scale);

	Init(mDesc);

	mCounter.Stop();
	LOG(_T("OBJMesh ") + file + _T(" ingelaad. Totale tijd: ") + mCounter.GetTime());
}

OBJMesh::~OBJMesh()
{
	m_Mesh->Release();
	m_Texture->Release();
	m_Layout->Release();
}

void OBJMesh::Init( const MeshDesc& mDesc )
{
	m_MeshDesc = mDesc;
	this->GetTotalTranspose();
	// NXActor
	NxActorDesc ActorDesc;
	D3DXComputeBoundingBox(&m_VertexList[0].m_Pos, m_VertexList.size(), sizeof(VertexAnim), &m_BoundingBox.minPt, &m_BoundingBox.maxPt);

	NxBoxShapeDesc BoxShapeDesc;
	D3DXVECTOR3 BBSize = m_BoundingBox.size();
	BoxShapeDesc.dimensions = NxVec3(BBSize.x / 2, BBSize.y/2, BBSize.z/2);
	BoxShapeDesc.mass = BBSize.x * BBSize.y * BBSize.z;
	ActorDesc.shapes.push_back(&BoxShapeDesc);
	NxMat34 mat;
	mat.setColumnMajor44(m_World);

	if(mDesc.state == MeshDesc::PhysxDynamic)
	{
		NxBodyDesc bodyDesc;
		bodyDesc.angularDamping	= 0.9f;
		bodyDesc.linearVelocity = NxVec3(0,0,0);
		//bodyDesc.mass = BBSize.x * BBSize.y * BBSize.z;
		ActorDesc.body = &bodyDesc;
	}

	ActorDesc.globalPose = mat;
	ActorDesc.density = 10.0f;

	m_Actor = PhysX::GetSingleton()->GetScene()->createActor(ActorDesc);

	HR(m_Mesh->SetVertexData(0, &m_VertexList[0]));
	HR(m_Mesh->SetIndexData(&m_IndexList[0], m_IndexList.size()));

	HR(m_Mesh->GenerateAdjacencyAndPointReps(0.001f));
	HR(m_Mesh->Optimize(D3DX10_MESHOPT_ATTR_SORT | D3DX10_MESHOPT_VERTEX_CACHE, 0, 0));
	HR(m_Mesh->GenerateGSAdjacency());
	HR(m_Mesh->CommitToDevice());

	if(m_TextureFile.size() != 0) {
		HR(D3DX10CreateShaderResourceViewFromFile(DXDEVICE->GetDevice(), m_TextureFile.c_str(), NULL, NULL, &m_Texture, NULL));
	}else{
		HR(D3DX10CreateShaderResourceViewFromFile(DXDEVICE->GetDevice(), _T("./Textures/WhiteTex.dds"), NULL, NULL, &m_Texture, NULL));
	}
}

void OBJMesh::Draw()
{
	//effect->SetMatrixen(m_World);
	//effect->SetTexture(m_Texture);
	//D3D10_TECHNIQUE_DESC tech;
	//effect->GetTech(step)->GetDesc( &tech);
	//for(UINT t = 0; t < tech.Passes; ++t)
	//{
	//	effect->GetTech(step)->GetPassByIndex(t)->Apply(0);
	//	m_Mesh->DrawSubset(0);
	//}
}

void OBJMesh::ReadVertice(tstring &line)
{
	vector<tstring> parseResult;
	StringUtil::Split(line, _T(" "), parseResult);
	if(parseResult.size() >= 4)
	{
		D3DXVECTOR3 vert;
		vert.x = static_cast<float>(tof(parseResult[1].c_str()));
		vert.y = static_cast<float>(tof(parseResult[2].c_str()));
		vert.z = static_cast<float>(tof(parseResult[3].c_str()));

		m_Vertices.push_back(vert);
	}
}

void OBJMesh::ReadNormal(tstring &line)
{
	vector<tstring> parseResult;
	StringUtil::Split(line, _T(" "), parseResult);
	if(parseResult.size() >= 4)
	{
		D3DXVECTOR3 vert;
		vert.x = static_cast<float>(tof(parseResult[1].c_str()));
		vert.y = static_cast<float>(tof(parseResult[2].c_str()));
		vert.z = static_cast<float>(tof(parseResult[3].c_str()));

		//LOG(StringUtil::ToString(vert.x) + _T(" | ") + StringUtil::ToString(vert.y) + _T(" | ") + StringUtil::ToString(vert.z));

		m_Normals.push_back(vert);
	}
}

void OBJMesh::ReadTexture(tstring &line)
{
	vector<tstring> parseResult;
	StringUtil::Split(line, _T(" "), parseResult);
	if(parseResult.size() >= 3)
	{
		D3DXVECTOR2 vert;
		vert.x = static_cast<float>(tof(parseResult[1].c_str()));
		vert.y = static_cast<float>(tof(parseResult[2].c_str()));

		m_TexCoords.push_back(vert);
		//LOG(StringUtil::ToString(vert.x) + _T(" | ") + StringUtil::ToString(vert.y));
	}
}

void OBJMesh::ReadFaces(tstring &line)
{
	vector<tstring> parseResult;
	StringUtil::Split(line, _T(" "), parseResult);
	if(parseResult.size() >= 4)
	{
		
		vector<tstring> result2;
		for(int t = 1; t < 4; ++t)
		{
			StringUtil::Split(parseResult[t], _T("/"), result2);
			FaceInfo info;
			info.vertex = static_cast<int>(tof(result2[0].c_str())) - 1;
			info.normal = static_cast<int>(tof(result2[2].c_str())) - 1;
			info.texcoord = static_cast<int>(tof(result2[1].c_str())) - 1;

			m_Faces.push_back(info);

		}
	}
}

void OBJMesh::ReadMaterial( tstring& line )
{
	vector<tstring> parseResult;
	StringUtil::Split(line, _T(" "), parseResult);
	if(parseResult.size() == 2)
		ReadMaterialFile(_T("./Models/OBJ/") + parseResult.at(1));
}

void OBJMesh::ReadMaterialFile( tstring& file )
{
	tifstream mat(file.c_str());
	if(!mat)
	{
		LOG(_T("ERROR: Kan ") + file + _T(" niet openen."));
		m_TextureFile = _T("");
	}else{

		tstring line;
		while(!mat.eof())
		{
			getline(mat, line);
			if(line.find(_T("map_Kd")) != string::npos)
			{
				vector<tstring> stringHelp;
				StringUtil::Split(line, _T(" "), stringHelp);
				m_TextureFile = _T("./Textures/") + stringHelp.at(1);
			}
		}
	}
}

const ID3D10ShaderResourceView* OBJMesh::GetTexture() const
{
	return m_Texture;
}

void OBJMesh::CalculateMesh()
{
	for(int t = 0; t < (int)m_Faces.size(); ++t)
	{
		FaceInfo fInfo = m_Faces.at(t);
		m_IndexList.push_back(m_VertexList.size());
		//LOG(StringUtil::ToString(fInfo.vertex + 1) + _T(" | ") + StringUtil::ToString(fInfo.texcoord + 1) + _T(" | ") +  StringUtil::ToString(fInfo.normal + 1));
		m_VertexList.push_back(Vertex(m_Vertices.at(fInfo.vertex), m_Normals.at(fInfo.normal), m_TexCoords.at(fInfo.texcoord), D3DXVECTOR3(0,0,0)));
	}
}